package cn.com.utils.crypto;

import cn.com.consts.MsgCd;
import cn.com.utils.WebUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import lombok.extern.slf4j.Slf4j;

import java.util.Base64;

/**
 * 国密加密实用程序
 *
 * @author LiuGuodong
 * @date 2024/03/20
 */
@Slf4j
public class SmCryptoUtil {

    private static final String PRIVATE_KEY = "sm2.private.key";
    private static final String PUBLIC_KEY = "sm2.public.key";

    private static final String SM_4_KEY = "sm4.key";


    private static final SM2 SM_2;

    private static final SymmetricCrypto SM_4;

    static {
        try {
            SM_2 = SmUtil.sm2(getBytes(SettingUtils.get(PRIVATE_KEY)), getBytes(SettingUtils.get(PUBLIC_KEY)));
            SM_4 = SmUtil.sm4(getBytes(SettingUtils.get(SM_4_KEY)));
        } catch (Exception e) {
            throw new RuntimeException(WebUtil.getMessage(MsgCd.ERR_MSG_BSS_1638171384));
        }
    }

    private static byte[] getBytes(String key) {
        return Base64.getDecoder().decode(key);
    }

    /**
     * SM_2解密数据。
     *
     * @param data 要解密的数据
     * @return 解密后的数据。
     */
    public static String sm2Decrypt(String data) {
        if (StrUtil.isBlank(data)) {
            return data;
        }
        try {
            return SM_2.decryptStrFromBcd(data, KeyType.PrivateKey);
        } catch (Exception e) {
            log.error("SM_2解密数据失败!");
        }
        return data;
    }


    /**
     * 使用SM_2加密数据。
     *
     * @param data 要加密的数据。
     * @return 加密的数据。
     */
    public static String sm2Encrypt(String data) {
        if (StrUtil.isBlank(data)) {
            return data;
        }
        try {
            return SM_2.encryptBcd(data, KeyType.PublicKey);
        } catch (Exception e) {
            log.error("使用SM_2加密数据失败!");
        }
        return data;
    }


    /**
     * 使用SM_3加密数据。
     *
     * @param data 要加密的数据。
     * @return 加密的数据。
     */
    public static String sm3Encrypt(String data) {
        if (StrUtil.isBlank(data)) {
            return data;
        }
        try {
            return SmUtil.sm3(data);
        } catch (Exception e) {
            log.error("使用SM_3加密数据失败!");
        }
        return data;
    }


    /**
     * sm4解密数据。
     *
     * @param data 要解密的数据
     * @return 解密后的数据。
     */
    public static String sm4Decrypt(String data) {
        if (StrUtil.isBlank(data)) {
            return data;
        }
        try {
            return StrUtil.utf8Str(SM_4.decryptStr(data));
        } catch (Exception e) {
            log.error("使用sm4解密数据失败!");
        }
        return data;
    }


    /**
     * 使用sm4加密数据。
     *
     * @param data 要加密的数据。
     * @return 加密的数据。
     */
    public static String sm4Encrypt(String data) {
        if (StrUtil.isBlank(data)) {
            return data;
        }
        try {
            return StrUtil.utf8Str(SM_4.encryptHex(data));
        } catch (Exception e) {
            log.error("使用sm4加密数据失败!");
        }
        return data;
    }


    public static void main(String[] args) {
        String text = "Hello, world!";

        String encryptHex = SmCryptoUtil.sm2Encrypt(text);
        System.out.println("加密后：" + encryptHex);
        String decryptStr = SmCryptoUtil.sm2Decrypt(encryptHex);
        System.out.println("解密后：" + decryptStr);
    }

}
